/* Reference source code is from:
 * www-personal.washtenaw.cc.mi.us/~chasselb/linux275/ClassNotes/ipc/shared_mem.htm */
/*********************************************************************/
/*********************************************************************/
/*                                                                   */
/* FUNCTION:  This program acts as a client to the server program.   */
/*            Simulate as the data mover.Move from *.264 to FPGA buf */
/*                                                                   */
/*                                                                   */
/*********************************************************************/
/*********************************************************************/

#include <stdio.h>
#include <string.h>
#include <sys/ipc.h>
#include <sys/stat.h>
#include <sys/sem.h>
#include <sys/shm.h>
#include "semshm.h"


int main(int argc, char *argv[])
{
    struct sembuf operations[3];
    void *shm_address;
    struct shared_buf *shared_stuff;
    int semid, shmid, rc;
    key_t semkey, shmkey;
    short  sarray[NUMSEMS];

    FILE *fp;
    struct stat inBuf;
    struct stat nextInBuf;
    int ret;
    char inFilePath[1024];
    char nextInFilePath[1024];
    int nRead;
    int running = 1;
    int nextFileReady = 0;
    unsigned int readIndex = 0;
    unsigned int nextReadIndex = 1;
    unsigned int tryReadCounter = 0;

    /* Generate an IPC key for the semaphore set and the shared      */
    /* memory segment.  Typically, an application specific path and  */
    /* id would be used to generate the IPC key.                     */
    semkey = ftok(SEMKEYPATH,SEMKEYID);
    if ( semkey == (key_t)-1 )
      {
        printf("main: ftok() for sem failed\n");
        return -1;
      }
    shmkey = ftok(SHMKEYPATH,SHMKEYID);
    if ( shmkey == (key_t)-1 )
      {
        printf("main: ftok() for shm failed\n");
        return -1;
      }

    /* Get the already created semaphore ID associated with key.     */
    /* If the semaphore set does not exist, then it will not be      */
    /* created, and an error will occur.                             */
    semid = semget( semkey, NUMSEMS, 0666);
    if ( semid == -1 )
      {
        printf("main: semget() failed\n");
        return -1;
      }

    /* Get the already created shared memory ID associated with key. */
    /* If the shared memory ID does not exist, then it will not be   */
    /* created, and an error will occur.                             */

    //shmid = shmget(shmkey, SIZEOFSHMSEG, 0666);
    shmid = shmget(shmkey, sizeof(struct shared_buf), 0666);
    if (shmid == -1)
      {
        printf("main: shmget() failed\n");
        return -1;
      }

    /* Attach the shared memory segment to the client process.       */
    shm_address = shmat(shmid, NULL, 0);
    if ( shm_address==NULL )
      {
        printf("main: shmat() failed\n");
        return -1;
      }

    /* Set the shared_stuff memory pointer */
    shared_stuff = (struct shared_buf *)shm_address;

    /* Enter the Read files loop */
    do
    {
	printf("\n#######################################################\n");
	/* Try to stat the next file */
	/* If next number of file does not exist, */
	/* goto sleep and count. If counter exceeds the max value,*/
	/* exit the program */
	sprintf(nextInFilePath,"rxbin_%d.264",nextReadIndex);
	printf("try to read next ");
	printf(nextInFilePath);printf("\n");
	nextFileReady = 0;
	while (!nextFileReady)
	{
	    ret = stat(nextInFilePath,&nextInBuf);
	    if (ret != 0)
	    {
		nextFileReady = 0;
		/* TODO: May Need some actions here */
		if(tryReadCounter > 500)
		{
		    printf("file rxbin_%d.264 does not exsist!\n",nextReadIndex);
		    goto error_out;
		}
		tryReadCounter++;
		usleep(10000);
	    }
	    else
		nextFileReady = 1;
	}
	nextReadIndex++;

	sprintf(inFilePath,"rxbin_%d.264",readIndex);
	printf("try to read current ");
	printf(inFilePath);printf(".........\n");
	ret = stat(inFilePath,&inBuf);
	if (ret != 0)
	{
	    printf("App, Mover: stat current file rxbin_%d.264 error!!\n",readIndex);
	    goto error_out;
	}
	readIndex++;

	fp = fopen(inFilePath,"rb");
	if (fp == NULL)
	{
	    printf("fopen failed ....\n");
	    return -1;
	}


#if 1
	printf("read index is : %d \n", readIndex);
	if ( readIndex >1 )
	{
	    rc = semctl( semid, 1, GETALL, sarray);
	    if(rc == -1)
	    {
		printf("main: semctl() getall failed\n");
		return -1;
	    }
	    printf("sarray is:%d, %d, %d\n",sarray[0], sarray[1], sarray[2]);
	    printf("semaphore, wait to be woke up by server!\n");
	    operations[0].sem_num = 2;  /* Operate on the second sem     */
	    operations[0].sem_op = -1;  /* Decrement the semval by one   */
	    operations[0].sem_flg = 0;  /* Allow a wait to occur         */

	    rc = semop( semid, operations, 1 );
	    if (rc == -1)
	    {
		printf("main: third semop() failed\n");
		return -1;
	    }
	    sleep(1);
	    printf("semaphore, after wait to be woke up by server!\n");
	    rc = semctl( semid, 1, GETALL, sarray);
	    if(rc == -1)
	    {
		printf("main: semctl() getall failed\n");
		return -1;
	    }
	    printf("sarray is:%d, %d, %d\n",sarray[0], sarray[1], sarray[2]);
	}
	else
	{
	    printf("semaphore, do not wait to be woke up by server!\n");
	}
#endif



	printf("Try to test and lock semaphore 1\n");
	/* First, check to see if the first semaphore is a zero.  If it  */
	/* is not, it is busy right now.  The semop() command will wait  */
	/* for the semaphore to reach zero before running the semop().   */
	/* When it is zero, increment the first semaphore to show that   */
	/* the shared memory segment is busy.                            */
	operations[0].sem_num = 0;	/* Operate on the first sem      */
	operations[0].sem_op =  0;	/* Wait for the value to be=0    */
	operations[0].sem_flg = 0;	/* Allow a wait to occur         */

	operations[1].sem_num = 0;	/* Operate on the first sem      */
	operations[1].sem_op =  1;      /* Increment the semval by one   */
	operations[1].sem_flg = 0;	/* Allow a wait to occur         */

	rc = semop( semid, operations, 2 );
	if (rc == -1)
	  {
	    printf("main: first semop() failed\n");
	    return -1;
	  }

	sleep(1);
	printf("Enter the critical section!\n");
	rc = semctl( semid, 1, GETALL, sarray);
	if(rc == -1)
	{
	    printf("main: semctl() getall failed\n");
	    return -1;
	}
	printf("sarray is:%d, %d, %d\n",sarray[0], sarray[1], sarray[2]);
	/* Enter the critical section */
	printf("data size is %d \n",(int)inBuf.st_size);
	shared_stuff->dataSize = inBuf.st_size;
	printf("data size is %d \n",shared_stuff->dataSize);
	nRead = fread(shared_stuff->buff,sizeof(int),inBuf.st_size/sizeof(int),fp);
	/* Leave the critical section */

	/* Release the shared memory segment by decrementing the in-use  */
	/* semaphore (the first one).  Increment the second semaphore to */
	/* show that the client is finished with it.                     */
	operations[0].sem_num = 0;	/* Operate on the first sem      */
	operations[0].sem_op =  -1;	/* Decrement the semval by one   */
	operations[0].sem_flg = 0;	/* Allow a wait to occur         */

	operations[1].sem_num = 1;	/* Operate on the second sem     */
	operations[1].sem_op =  1;	/* Increment the semval by one   */
	operations[1].sem_flg = 0;	/* Allow a wait to occur         */

	rc = semop( semid, operations, 2 );
	if (rc == -1)
	{
	    printf("main: second semop() failed\n");
	    return -1;
	}
	sleep(1);
	rc = semctl( semid, 1, GETALL, sarray);
	if(rc == -1)
	{
	    printf("main: semctl() getall failed\n");
	    return -1;
	}
	printf("sarray is:%d, %d, %d\n",sarray[0], sarray[1], sarray[2]);
	printf("Already leave the critical section!\n");

#if 0

	if ( readIndex >=1 )
	{
	    printf("semaphore, wait to be woke up by server!\n");
	    operations[0].sem_num = 2;  /* Operate on the second sem     */
	    operations[0].sem_op = -1;  /* Decrement the semval by one   */
	    operations[0].sem_flg = 0;  /* Allow a wait to occur         */

	    rc = semop( semid, operations, 1 );
	    if (rc == -1)
	    {
		printf("main: third semop() failed\n");
		return -1;
	    }
	    sleep(1);
	    printf("semaphore, after wait to be woke up by server!\n");
	    rc = semctl( semid, 1, GETALL, sarray);
	    if(rc == -1)
	    {
		printf("main: semctl() getall failed\n");
		return -1;
	    }
	    printf("sarray is:%d, %d, %d\n",sarray[0], sarray[1], sarray[2]);
	}
	else
	{
	    printf("semaphore, do not wait to be woke up by server!\n");
	}
#endif

	fclose(fp);
    }while(running);

error_out:
    /* Detach the shared memory segment from the current process.    */
    rc = shmdt(shm_address);
    if (rc==-1)
      {
        printf("main: shmdt() failed\n");
        return -1;
      }

return 0;
}
